[Amazon Bedrock] 簡単な下絵から、多数のイラストを自動生成してアイデアを膨らませる
1 はじめに
CX 事業本部 delivery部の平内(SIN)です。
Amazon Bedrockを使用することで、生成AIを軽易に利用することが可能ですが、カテゴリ「Image」に分類される、Stability AI の Stable Diffusion XL(Preview) では、画像の生成が可能になっています。
生成AIで画像作成する場合、入力するプロンプトが、非常に大きな影響を与えますが、思った通りの出力を得ることは、比較的難しい作業となります。このため、ビジネスのシーン等で、即戦力として活用するのは、まだ、ちょっとハードルの高いものになっているかも知れません。
そこで、今回は、イラストなどの作成時に、簡単な下絵を書いて、そこから、「アイデアを膨らませるために、たくさんのサンプルを生成する」というイメージで作業してみました。
2 フリーハンド
最初にフリーハンドで書いた絵で試してます。(絵心のカケラもない私が、頑張って書いたイラストです)
設定したプロンプトは、以下のとおりです。
prompt = "cute puppy,light smile, In front of the doghouse with the red roof,illustration"
3 パワーポイント
次は、パワーポイントで頑張って書いた絵で試しました。
プロンプトは、以下のとおりです。
prompt = "sticker illustration of cute puppy,light smile, In front of the doghouse with the red roof,vectorized"
4 作業手順
作業は、実装した create_sample_illustration.pyと、下絵を配置して行います。
% tree . . ├── create_sample_illustration.py └── dog.png
実行すると、6枚の画像が生成されます。
% python3 create_sample_illustration.py 20231009_021923.png 20231009_021930.png 20231009_021935.png 20231009_021940.png 20231009_021945.png 20231009_021950.png
. ├── create_sample_illustration.py ├── data │ ├── 20231009_021923.json │ ├── 20231009_021923.png │ ├── 20231009_021930.json │ ├── 20231009_021930.png │ ├── 20231009_021935.json │ ├── 20231009_021935.png │ ├── 20231009_021940.json │ ├── 20231009_021940.png │ ├── 20231009_021945.json │ ├── 20231009_021945.png │ ├── 20231009_021950.json │ ├── 20231009_021950.png │ └── sample_20231009_021950.png └── dog.png
xxxxxx_xxxxxx.pngが、サイズ(512*512)の生成された画像で、xxxxxx_xxxxxx.jsonが、その諸元です。また、最後に、sample_xxxxxx_xxxxxx.pngが出力されますが、こちらは、作成された6枚の絵を一覧できるように合成した画像となります。
5 create_sample_illustration.py
コードは、大きくは、「イラストを生成するクラス(IllustrationGenerator)」と、最後に「サンプル画像を生成するクラス(Sample_Images)」の2つで構成されています。
Stable Diffusion XLを使用してい、boto3で画像生成しているのは、前者のIllustrationGeneratorです。
import io import math import os import json import datetime import random import base64 from PIL import Image, ImageDraw, ImageFont import boto3 # サンプル画像を生成するクラス class Sample_Images: def __init__(self, size): self.index = 0 self.size = size self.create_max = 6 font_path = "/System/Library/Fonts/ヒラギノ角ゴシック W5.ttc" self.font_size = 30 height = math.floor(self.size * (self.create_max / 3)) width = math.floor(self.size * (self.create_max / 2)) self.base_image = Image.new("RGB", (width, height)) self.draw = ImageDraw.Draw(self.base_image) self.font = ImageFont.truetype(font_path, size=self.font_size) def append(self, image, name): x = int(self.index % (self.create_max / 2) * self.size) y = int(math.floor(self.index / (self.create_max / 2)) * self.size) self.base_image.paste(image, (x, y)) self.draw.text( (x, y + self.size - self.font_size - 5), name, fill=(0, 0, 0), font=self.font, ) self.index += 1 def save(self, filename): self.base_image = self.base_image.resize((900, 600)) self.base_image.save(filename) # イラストを生成するクラス class IllustrationGenerator: def __init__(self, size, prompt, data_path, input_image): self.boto3_bedrock = boto3.client("bedrock-runtime", region_name="us-east-1") self.model_id = "stability.stable-diffusion-xl" self.size = size self.data_path = data_path # パラメータ self.config = { "filename": "", "seed": 0, "prompt": prompt, "size": self.size, "steps": 50, "cfg_scale": 30, "start_schedule": 0.6, "style_preset": "anime", "input_image": input_image, } # 入力画像 self.input_image_b64 = self.__image_to_base64( Image.open(input_image).resize((self.size, self.size)) ) def __image_to_base64(self, image): buffer = io.BytesIO() image.save(buffer, format="PNG") return base64.b64encode(buffer.getvalue()).decode("utf-8") def __base64_to_image(self, base64_str): return Image.open(io.BytesIO(base64.decodebytes(bytes(base64_str, "utf-8")))) def create(self): # 日時文字列をファイル名に使用する basename = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") # 毎回変化する設定値 self.config["filename"] = basename + ".png" self.config["seed"] = random.randint(0, 100000) # 入力パラメータ body = json.dumps( { "text_prompts": [{"text": self.config["prompt"], "weight": 1.0}], "cfg_scale": self.config["cfg_scale"], "seed": self.config["seed"], "start_schedule": self.config["start_schedule"], "steps": self.config["steps"], "style_preset": self.config["style_preset"], "init_image": self.input_image_b64, } ) # 推論 response = self.boto3_bedrock.invoke_model(body=body, modelId=self.model_id) # 推論結果の画像取得 response_body = json.loads(response.get("body").read()) response_image = self.__base64_to_image( response_body["artifacts"][0].get("base64") ) # レスポンス画像の保存 response_image.save("{}/{}.png".format(self.data_path, basename)) # 設定値の保存 with open("{}/{}.json".format(self.data_path, basename), "w") as f: json.dump(self.config, f, ensure_ascii=False) # 生成された画像と名前を返す return (response_image, basename) def main(): size = 512 data_path = "./data" if not os.path.exists(data_path): os.makedirs(data_path) # 元画像 input_image = "./dog.png" # 作成するイラストの説明 # prompt = "cute puppy,light smile, In front of the doghouse with the red roof,illustration" prompt = "sticker illustration of cute puppy,light smile, In front of the doghouse with the red roof,vectorized" # サンプル画像をまとめるクラス sample_images = Sample_Images(size) # イラスト生成クラス illustration_generator = IllustrationGenerator(size, prompt, data_path, input_image) for i in range(6): (image, basename) = illustration_generator.create() sample_images.append(image, "{}.png".format(basename)) print("{}.png".format(basename)) sample_images.save("{}/sample_{}.png".format(data_path, basename)) if __name__ == "__main__": main()
6 最後に
今回は、アイデア出しのために、簡単な下絵から、たくさんのイラストを生成する作業をやってみました。
オンデマンドで使用する Stable Diffusion XL のコストは、1枚、$0.018です。
(サイズ 512*512 以下 ステップ 51以下の場合の料金です。上記のコードは、この範囲内で動作してます)
これぐらいのコストであれば、多くのサンプルを出力して、スピーディーにより良いアイデアが得られれば、費用対効果は大きいのではと思いました。
※「フリーハンド」と「パワーポイント」の違いは、微妙ですが、一応、差が出ているような気がしてます。